package lexer;
import java.io.*; 
import java.util.*; 
import symbols.*;

public class Lexer {
    
   public static int line = 1;
   
   char peek = ' ';
   
   Hashtable words = new Hashtable();
   
   void reserve(Word w) 
   { 
       words.put(w.lexeme, w); 
   }

   public Lexer() {

      reserve( new Word("if",    Tag.IF)    );
      reserve( new Word("else",  Tag.ELSE)  );
      reserve( new Word("while", Tag.WHILE) );
      reserve( new Word("do",    Tag.DO)    );
      reserve( new Word("break", Tag.BREAK) );

      reserve( Word.True );  
      reserve( Word.False );

      reserve( Type.Int  );  
      reserve( Type.Char  );
      reserve( Type.Bool );  
      reserve( Type.Float );
   }

   void readch() throws IOException 
   { 
       peek = (char)System.in.read(); 
   }
   boolean readch(char c) throws IOException 
   {
      readch();
      
      if( peek != c ) 
          return false;
      
      peek = ' ';
      
      return true;
   }
   public Token scan() throws IOException 
   {
      for( ; ; readch() )
      {
         if( peek == ' ' || peek == '\t' ) 
             continue;
         
         else if( peek == '\n' ) 
             line = line + 1;
         
         else 
             break;
      }
      switch( peek ) {
      case '&':
         if( readch('&') ) return Word.and;  else return new Token('&');
      case '|':
         if( readch('|') ) return Word.or;   else return new Token('|');
      case '=':
         if( readch('=') ) return Word.eq;   else return new Token('=');
      case '!':
         if( readch('=') ) return Word.ne;   else return new Token('!');
      case '<':
         if( readch('=') ) return Word.le;   else return new Token('<');
      case '>':
         if( readch('=') ) return Word.ge;   else return new Token('>');
      }
      if( Character.isDigit(peek) ) {
         int v = 0;
         do {
             
            v = 10*v + Character.digit(peek, 10); 
            readch();
            
         } while( Character.isDigit(peek) );
         
         if( peek != '.' ) 
             return new Num(v);
         
         float x = v; 
         float d = 10;
         
         for(;;) 
         {
            readch();
            if( ! Character.isDigit(peek) ) 
                break;
            x = x + Character.digit(peek, 10) / d;
            d = d*10;
         }
         return new Real(x);
      }
      if( Character.isLetter(peek) ) 
      {
         StringBuffer b = new StringBuffer();
         
         do {
             
            b.append(peek); 
            readch();
         } while( Character.isLetterOrDigit(peek) );
         
         String s = b.toString();
         
         Word w = (Word)words.get(s);
         
         if( w != null ) 
             return w;
         
         w = new Word(s, Tag.ID);
         
         words.put(s, w);
         
         return w;
      } 
      Token tok = new Token(peek); 
      peek = ' ';
      return tok;
   }
}
